package net.pulseproject.commons.gui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.StringSelection;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.WindowConstants;

import net.pulseproject.commons.util.GuiUtil;
import net.pulseproject.commons.util.StringUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.google.inject.Inject;
import com.google.inject.assistedinject.Assisted;

public class ExceptionDialog extends JDialog {
	
	private static final Log LOG = LogFactory.getLog(ExceptionDialog.class);
	
	private static final long serialVersionUID = 6916895374719464428L;
	
	private final Icon errorIcon;
	
//	public static void main(final String[] args) {
//		final JFrame frame = new JFrame();
//		frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//		frame.setVisible(true);
//		new ExceptionDialog(frame, new Exception("Technical details are included here."),
//				"Some error specific message.").setVisible(true);
//	}
	
	@Inject
	public ExceptionDialog(
			final IconsCache iconsCache,
			@Assisted final JFrame parent,
			@Assisted final Exception exception,
			@Assisted final String message) {
		super(parent);
		this.errorIcon = iconsCache.load(IconType.ERROR_ICON);
		
		if(parent == null) { throw new IllegalArgumentException("parent == null"); }
		if(exception == null) { throw new IllegalArgumentException("exception == null"); }
		if(message == null) { throw new IllegalArgumentException("message == null"); }
		
		this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
		this.setTitle("Unhandled Exception");
		
		final JPanel panel = new JPanel();
		panel.setLayout(new BorderLayout());
		panel.setBorder(BorderFactory.createEmptyBorder(7, 20, 3, 20));
		
		final String exceptionStackTrace = StringUtil.exceptionToString(exception);
		panel.add(this.createNorthPanel(exception, message), BorderLayout.NORTH);
		panel.add(this.createExceptionTextArea(exceptionStackTrace), BorderLayout.CENTER);
		panel.add(this.createSouthPanel(exceptionStackTrace), BorderLayout.SOUTH);
		
		this.add(panel);
		this.setSize(550, 240);
		GuiUtil.setCenterLocation(this);
	}
	
	private Component createExceptionTextArea(final String exceptionStackTrace) {
		final Font font = new Font("Monaco", Font.PLAIN, 11);
		
		final JTextArea textArea = new JTextArea();
		textArea.setEditable(false);
		textArea.setFont(font);
		textArea.setText(exceptionStackTrace);
		
		return new JScrollPane(textArea);
	}

	private JPanel createNorthPanel(final Exception exception, final String message) {
		final JPanel northPanel = new JPanel(new BorderLayout(10, 0));
		northPanel.add(new JLabel(this.errorIcon), BorderLayout.WEST);
		
		final JPanel messagePanel = new JPanel();
		messagePanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));
		messagePanel.setLayout(new BoxLayout(messagePanel, BoxLayout.Y_AXIS));
		
		final JLabel messageLabel = new JLabel(message);
		messageLabel.setBorder(BorderFactory.createEmptyBorder(0, 0, 4, 0));
		messagePanel.add(messageLabel);
		
		messagePanel.add(new JLabel(exception.getClass().getSimpleName() + ": " + 
				(exception.getMessage() != null ? exception.getMessage() : "N/A")));
		northPanel.add(messagePanel, BorderLayout.CENTER);
		return northPanel;
	}

	private JPanel createSouthPanel(final String exceptionStackTrace) {
		final JPanel southPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
		
		final JButton copyButton = new JButton("Copy to Clipboard");
		copyButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent event) {
				ExceptionDialog.this.copyToClipboard(exceptionStackTrace);
			}
		});
		southPanel.add(copyButton);
		
		final JButton closeButton = new JButton("Close");
		this.getRootPane().setDefaultButton(closeButton);
		closeButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent event) {
				ExceptionDialog.this.dispose();
			}
		});
		southPanel.add(closeButton);
		
		return southPanel;
	}
	
	// TODO outsource copyToClipboard method
	private void copyToClipboard(final String textToCopy) {
		LOG.info("copyToClipboard(textToCopy)");
		
		final StringSelection stringSelection = new StringSelection(textToCopy);
		final Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
		clipboard.setContents(stringSelection, new ClipboardOwner() {
			@Override
			public void lostOwnership(final Clipboard clipbaord, final Transferable transferable) {
				LOG.debug("lostOwnership(clipbaord, transferable)");
			}
		});
	}
	
}
